﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Pavilion;

namespace Pavilion.GameTools
{
    public class PhysicalTypeTool : GameToolBase
    {
        public static readonly Dictionary<string, PhysicalData> PhysicalDataCollection = new Dictionary<string, PhysicalData>();

        private PolygonCollisionData physicalCollisionData;
        private MultiLineCollisionData multiLineCollisionData;
        private Color boxColor = Color.Black;
        private GroundState groundState;

        public PolygonPhysicalData PolygonData { get; private set; }
        public GroundState GroundState { get { return groundState; } private set { groundState = value; OnPropertyChanged("GroundState"); } }

        public PhysicalTypeTool() : base()
        {
            PolygonData = new PolygonPhysicalData();

            DataExecutionDictionary.Add("Momentum", (value) => PolygonData.Momentum = (Momentum)value);
            DataExecutionDictionary.Add("PhysicalState", (value) => PolygonData.PhysicalState = (PhysicalState)value);
            DataExecutionDictionary.Add("IsFlippedHorizontally", (value) => PolygonData.IsFlippedHorizontally = (bool)value);
            DataExecutionDictionary.Add("SpeedX", (value) => PolygonData.SpeedX = (float)value);
            DataExecutionDictionary.Add("SpeedY", (value) => PolygonData.SpeedY = (float)value);
            DataExecutionDictionary.Add("Speed", (value) =>
            {
                string[] speedValues = (value as string).Split(',');

                PolygonData.SpeedX = float.Parse(speedValues[0]);
                PolygonData.SpeedY = float.Parse(speedValues[1]);
            });
            DataExecutionDictionary.Add("PhysicalBounds", (value) =>
            {
                string[] points = (value as string).Split(',');

                PolygonData.PhysicalBounds.BeginChanges();
                PolygonData.PhysicalBounds.Clear();

                for (int i = 0; i < points.Length; i += 2)
                    PolygonData.PhysicalBounds.Add(new Vector2(float.Parse(points[i]) + PolygonData.Position.X, float.Parse(points[i + 1]) + PolygonData.Position.Y));

                PolygonData.PhysicalBounds.EndChanges();
            });
        }

        public override void Initialize(GameItem gameItem)
        {
            if (!PhysicalDataCollection.ContainsKey(gameItem.Name) && gameItem.IsEnabled)
                PhysicalDataCollection.Add(gameItem.Name, PolygonData);

            gameItem.Disposed += () => PhysicalDataCollection.Remove(gameItem.Name);
            gameItem.UpdateLogic += (GameTime gameTime) => PolygonData.MoveBySpeed();

            CollisionManager.Instance.AddPolygonData(PolygonData, MultiLineCollisionDataChanged, (p) => UpdateBoxColor());
            physicalCollisionData = CollisionManager.Instance.GetPolygonToPolygonsData(PolygonData);
            multiLineCollisionData = CollisionManager.Instance.GetPolygonToMultiLinesData(PolygonData);

            UpdateGroundState(multiLineCollisionData.InteresectedLines);

            DrawManager.Instance.Add(new DrawItem(20, () => DrawManager.Instance.DrawPolygonBox(PolygonData.PhysicalBounds, boxColor)));
        }

        public override void Deserialize(XElement xmlProperties)
        {
            PolygonData.SetPosition(int.Parse(xmlProperties.Attribute("PositionX").Value), int.Parse(xmlProperties.Attribute("PositionY").Value));
            PolygonData.Size = float.Parse(xmlProperties.Attribute("Size").Value);
        }

        public override void Serialize()
        {
            throw new NotImplementedException();
        }

        private void MultiLineCollisionDataChanged(MultiLineCollisionData collisionData)
        {
            UpdateBoxColor();

            UpdateGroundState(collisionData.InteresectedLines);
        }

        private void UpdateGroundState(List<LineVector> interestectedLines)
        {
            if (interestectedLines.Count > 0)
                GroundState = GroundState.SolidGround;
            else
                GroundState = GroundState.NoGround;
        }

        private void UpdateBoxColor()
        {
            if (physicalCollisionData.InteresectedPolygons.Count > 0 && multiLineCollisionData.InteresectedLines.Count > 0)
                boxColor = Color.Orange;
            else if (physicalCollisionData.InteresectedPolygons.Count > 0)
                boxColor = Color.Red;
            else if (multiLineCollisionData.InteresectedLines.Count > 0)
                boxColor = Color.Green;
            else
                boxColor = Color.Black;
        }
    }

    public struct PhysicalTypeData : IGameDataInfo
    {
        public string ToolName { get { return typeof(PhysicalTypeTool).Name; } }
        public Dictionary<string, GamePropertyInfo> DataConversionDictionary { get { return (dataConversionDictionary == null) ? LoadDataConversion() : dataConversionDictionary; } }
        public IEnumerable<string> CompletePropertyList { get { return DataConversionDictionary.Keys; } }

        private static Dictionary<string, GamePropertyInfo> dataConversionDictionary;

        public GamePropertyInfo ObtainPropertyInfo(string propertyName)
        {
            return DataConversionDictionary[propertyName];
        }

        private static Dictionary<string, GamePropertyInfo> LoadDataConversion()
        {
            dataConversionDictionary = new Dictionary<string, GamePropertyInfo>();

            dataConversionDictionary.Add("Momentum", new GamePropertyInfo((propertyValue) => GameEngine.EnumParse<Momentum>(propertyValue), default(Momentum)));
            dataConversionDictionary.Add("PhysicalState", new GamePropertyInfo((propertyValue) => GameEngine.EnumParse<PhysicalState>(propertyValue), default(PhysicalState)));
            dataConversionDictionary.Add("SpeedX", new GamePropertyInfo((propertyValue) => float.Parse(propertyValue), default(float)));
            dataConversionDictionary.Add("SpeedY", new GamePropertyInfo((propertyValue) => float.Parse(propertyValue), default(float)));
            dataConversionDictionary.Add("IsFlippedHorizontally", new GamePropertyInfo((propertyValue) => bool.Parse(propertyValue), default(bool)));
            dataConversionDictionary.Add("Speed", new GamePropertyInfo((x) => x, "0,0"));
            dataConversionDictionary.Add("PhysicalBounds", new GamePropertyInfo((x) => x, ""));

            return dataConversionDictionary;
        }
    }

    public enum GroundState
    {
        SolidGround,
        SwampGround,
        NoGround,
    }
}
